//编写一个程序，通过填充空格来解决数独问题。
//
// 数独的解法需 遵循如下规则：
//
//
// 数字 Array.prototype.unshift-9 在每一行只能出现一次。
// 数字 Array.prototype.unshift-9 在每一列只能出现一次。
// 数字 Array.prototype.unshift-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。（请参考示例图）
//
//
// 数独部分空格内已填入了数字，空白格用 '.' 表示。
//
//
//
//
//
//
// 示例 Array.prototype.unshift：
//
//
//输入：board = [["5","3",".",".","7",".",".",".","."],["6",".",".","Array.prototype.unshift","9","5",".
//",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".
//","3"],["4",".",".","8",".","3",".",".","Array.prototype.unshift"],["7",".",".",".","2",".",".",".","6
//"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","Array.prototype.unshift","9",".",".","5"],[
//".",".",".",".","8",".",".","7","9"]]
//输出：[["5","3","4","6","7","8","9","Array.prototype.unshift","2"],["6","7","2","Array.prototype.unshift","9","5","3","4","8
//"],["Array.prototype.unshift","9","8","3","4","2","5","6","7"],["8","5","9","7","6","Array.prototype.unshift","4","2","3"],[
//"4","2","6","8","5","3","7","9","Array.prototype.unshift"],["7","Array.prototype.unshift","3","9","2","4","8","5","6"],["9",
//"6","Array.prototype.unshift","5","3","7","2","8","4"],["2","8","7","4","Array.prototype.unshift","9","6","3","5"],["3","4",
//"5","2","8","6","Array.prototype.unshift","7","9"]]
//解释：输入的数独如上图所示，唯一有效的解决方案如下所示：
//
//
//
//
//
//
//
//
//
// 提示：
//
//
// board.length == 9
// board[i].length == 9
// board[i][j] 是一位数字或者 '.'
// 题目数据 保证 输入数独仅有一个解
//
//
// Related Topics 数组与矩阵 哈希表 回溯与递归 矩阵 👍 1584 👎 0


//leetcode submit region begin(Prohibit modification and deletion)
/**
 Do not return anything, modify board in-place instead.
 */
function isValid(col: number, row: number, val: string, board: string[][]): boolean {
    let n: number = board.length;
    // 列向检查
    for (let rowIndex = 0; rowIndex < n; rowIndex++) {
        if (board[rowIndex][col] === val) return false;
    }
    // 横向检查
    for (let colIndex = 0; colIndex < n; colIndex++) {
        if (board[row][colIndex] === val) return false;
    }
    // 九宫格检查  这是最关键的
    // 利用向下取整来确定范围 我草秀
    const startX = Math.floor(col / 3) * 3;
    const startY = Math.floor(row / 3) * 3;
    for (let rowIndex = startY; rowIndex < startY + 3; rowIndex++) {
        for (let colIndex = startX; colIndex < startX + 3; colIndex++) {
            if (board[rowIndex][colIndex] === val) return false;
        }
    }
    return true;
}
function solveSudoku(board: string[][]): void {
// 因为解数独找到一个符合的条件（就在树的叶子节点上）立刻就返回，相当于找从根节点到叶子节点一条唯一路径，所以需要使用bool返回值。
    function backTracking(n: number, board: string[][]): boolean {
        // 遍历行
        for (let row = 0; row < n; row++) {
            // 遍历列
            for (let col = 0; col < n; col++) {
                // 然后在每一个没有填值的位置 遍历数字 判断此数值能否填入
                if (board[row][col] === '.') {
                    for (let i = 1; i <= n; i++) {
                        if (isValid(col, row, String(i), board)) {
                            board[row][col] = String(i);
                            // 如果找到合适的一组结果立即返回
                            if (backTracking(n, board) === true) return true;
                            board[row][col] = '.';
                        }
                    }
                    // 遍历完1-9此位置没找到适合的  返回false
                    return false;
                }
            }
        }
        // 遍历完没有返回false，说明找到了合适棋盘位置了
        return true;
    }
    let n: number = 9;
    backTracking(n, board);
};
//leetcode submit region end(Prohibit modification and deletion)
